#ifndef MineCraftSceneData_H
#define MineCraftSceneData_H

#include <QtQmlIntegration>
#include <QTransform>
#include <QMatrix4x4>
#include <minecraftblocklibrary.h>
#include <QUrl>

class MineCraftSceneData;
class MineCraftSceneBuilder;
class MineCraftSceneBrush:public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_UNCREATABLE("")
public:
    MineCraftSceneBrush();

protected:
    virtual BlockMeta::BlockType getBlock(const QVector3D& position) = 0;
    friend class MineCraftSceneBuilder;
};

//默认画刷
class MineCraftDefaultBrush:public MineCraftSceneBrush
{
    Q_OBJECT
    QML_ELEMENT
public:
    MineCraftDefaultBrush();

    BlockMeta::BlockType getBlock(const QVector3D& position) override;
    BlockMeta::BlockType type() const;
    void setType(const BlockMeta::BlockType &newType);

signals:
    void typeChanged();

private:
    BlockMeta::BlockType m_type = BlockMeta::None;

    Q_PROPERTY(BlockMeta::BlockType type READ type WRITE setType NOTIFY typeChanged FINAL)
};

class MineCraftRandomBrush:public MineCraftSceneBrush
{
    Q_OBJECT
    QML_ELEMENT
public:
    MineCraftRandomBrush();

    BlockMeta::BlockType getBlock(const QVector3D& position) override;
    int getSeed() const;
    void setSeed(int newSeed);

    BlockMeta::BlockType type() const;
    void setType(const BlockMeta::BlockType &newType);
    float threthold() const;
    void setThrethold(float newThrethold);

signals:
    void seedChanged();
    void typeChanged();
    void thretholdChanged();

private:
    int seed = 0;
    float m_threthold = 0.5;
    BlockMeta::BlockType m_type = BlockMeta::None;
    QRandomGenerator gen;

    Q_PROPERTY(int seed READ getSeed WRITE setSeed NOTIFY seedChanged FINAL)
    Q_PROPERTY(BlockMeta::BlockType type READ type WRITE setType NOTIFY typeChanged FINAL)
    Q_PROPERTY(float threthold READ threthold WRITE setThrethold NOTIFY thretholdChanged FINAL)
};

class MineCraftSceneBuilder:public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_UNCREATABLE("")

public:
    enum BuildMode//构建模式
    {
        Add,//增加模式，只会影响为空的位置
        Override,//覆盖模式
        Modify,//修改模式，只会影响不为空的位置
        Remove//擦除模式
    };
    Q_ENUM(BuildMode);
private:
    struct Context
    {
        BuildMode buildMode = Add;//绘制模式
        MineCraftSceneBrush* brush = nullptr;//画刷
        QVariant custom;//自定义数据
        QVector3D blockRotation = {};//方块的朝向
        QMatrix4x4 transform;//坐标转换
        QTransform t;
    };
    typedef QList<Context> ContextList;
public:
    MineCraftSceneBuilder();

    Q_INVOKABLE void push();//保存当前的绘图上下文
    Q_INVOKABLE void pop();//弹出当前的绘图上下文
    Q_INVOKABLE void reset();//重新设置当前的绘图上下文


    Q_PROPERTY(BuildMode buildMode READ buildMode WRITE setBuildMode NOTIFY buildModeChanged)
    Q_PROPERTY(QVector3D blockRotation READ blockRotation WRITE setBlockRotation NOTIFY blockRotationChanged)
    Q_PROPERTY(QVariant customData READ customData WRITE setCustomData NOTIFY customDataChanged)
    Q_PROPERTY(MineCraftSceneBrush* brush READ brush WRITE setBrush NOTIFY brushChanged)

    MineCraftSceneBrush* brush();
    void setBrush(MineCraftSceneBrush* brush);

    BuildMode buildMode();
    void setBuildMode(BuildMode mode);

    QVector3D blockRotation();
    void setBlockRotation(QVector3D rotation);

    QVariant customData();
    void setCustomData(QVariant v);

    Q_INVOKABLE void translate(QVector3D position);//画笔移动到某个地方（右乘）
    Q_INVOKABLE void rotate(QVector3D rotation);//画笔旋转

    Q_INVOKABLE void drawBlock(QVector3D point);//绘制一格方块
    Q_INVOKABLE void drawBox(QVector3D start,QVector3D extends);//绘制一个实心方块
    Q_INVOKABLE void drawBoxShell(QVector3D start,QVector3D extends);//绘制一个空心方块
    Q_INVOKABLE void drawBoxFrame(QVector3D start,QVector3D extends);//绘制一个方块框架
    MineCraftDefaultBrush *defaultBrush() const;
    void setDefaultBrush(MineCraftDefaultBrush *newDefaultBrush);

signals:
    void buildModeChanged();
    void blockRotationChanged();
    void customDataChanged();
    void defaultBrushChanged();
    void brushChanged();

private:
    QVector3D mapPoint(QVector3D point);
    void applyBlock(QVector3D point);
    Context& curCtx();//当前的上下文
private:
    ContextList m_ctxs;
    MineCraftDefaultBrush* m_defaultBrush = nullptr;//默认画刷
    MineCraftSceneData* scene = nullptr;
    friend class MineCraftSceneData;
    Q_PROPERTY(MineCraftDefaultBrush *defaultBrush READ defaultBrush WRITE setDefaultBrush NOTIFY defaultBrushChanged FINAL)
};

class MineCraftSceneData:public QObject
{
    Q_OBJECT
    QML_ELEMENT
public:

    MineCraftSceneData();
    struct BlockData
    {
        BlockMeta::BlockType type = BlockMeta::None;
        QVector3D rotation;
        QVariant custom;
    };
    struct WorldData
    {
        WorldData(){

        }

        WorldData(WorldData&& other)
        {
            move(other);
        }

        void operator =(WorldData&& other)
        {
            move(other);
        }

        void move(WorldData& other){
            clean();
            blocks = other.blocks;
            extend = other.extend;
            other.blocks = nullptr;
            other.extend = {};
        }

        void clean(){
            if(blocks)
            {
                delete [] blocks;
                blocks = nullptr;
            }
            extend = {};
        }

        ~WorldData(){
            clean();
        }
        BlockData* blocks = nullptr;
        QVector3D extend;
    };

    QVector3D extend() const;
    void setExtends(const QVector3D &newExtends);

public:
    Q_INVOKABLE void requestRebuild();//请求重新绘制

    MineCraftSceneData::BlockData* get(int x,int y,int z)
    {
        return get(m_world,x,y,z);
    }

    MineCraftSceneData::BlockData* get(WorldData & world,int x,int y,int z)
    {
        const auto& extend = world.extend;
        if(x < 0 || x >=extend.x())
        {
            return nullptr;
        }
        if(y < 0 || y >=extend.y())
        {
            return nullptr;
        }
        if(z < 0 || z >=extend.z())
        {
            return nullptr;
        }

        return world.blocks + int(y * (extend.x() * extend.z()) + z * extend.x() + x);
    }
    MineCraftSceneBuilder *getBuilder() const;


signals:
    void extendChanged();
    void rebuild();//重新绘制
    void buildFinished();
    void builderChanged();

private:
    void setBuilder(MineCraftSceneBuilder *newBuilder);
    void resize(QVector3D newSize);
private:
    WorldData m_world;
    MineCraftSceneBuilder* builder = nullptr;
    bool m_building = false;
    Q_PROPERTY(QVector3D extend READ extend WRITE setExtends NOTIFY extendChanged FINAL)
    friend class MineCraftSceneBuilder;
    Q_PROPERTY(MineCraftSceneBuilder *builder READ getBuilder NOTIFY builderChanged FINAL)
};

#endif
